﻿/********************************************************************************************
 * 文件名称:	EntityInitialHander.cs
 * 设计人员:	严向晖
 * 设计时间:	2007-09-12
 * 功能描述:	根据实体映射文档，对实体进行初始化赋值
 *		
 *		
 * 注意事项:	
 *
 * 版权所有:	Copyright (c) 2007, Fujian SIRC
 *
 * 修改记录: 	修改时间		人员		修改备注
 *				----------		------		-------------------------------------------------
 *
 ********************************************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Xml;
using System.Xml.XPath;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;
using Sgml;
using System.Net;

namespace SIRC.Framework.Net
{
    /// <summary>
    /// 根据实体映射文档<seealso cref="EntityXpathInfo"/>对实体进行初始化赋值
    /// </summary>
    /// <typeparam name="T">客户端定义的实体对象，必须是引用类型</typeparam>
    public class EntityInitialHander<T> where T : IConvert<T>, new()
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="eInfo"></param>
        /// <returns></returns>
        public T GetEntityFromXpath(EntityXpathInfo eInfo)
        {
            // html->xml
            //string htmlString = new WebDownloader().GetContentByUrl(eInfo.URL);
            //string htmlString = GetWellFormedHTML(eInfo.URL, eInfo.ProperyMapInfo[0].Xpath);
            //XmlDocument xmlDoc = new XmlDocument();
            //string filename = @"D:\dotNetProject\2005\Projects\SharpMovie\SharpMClient\Test.xml";
            //xmlDoc.Load(filename);
            XmlDocument xmlDoc = ConvertHtml2Xml(eInfo.URL, "gb2312");
            // 实体赋值
            T t = new T();
            Type type = typeof(T);
            // 设置属性
            PropertyInfo[] proList = type.GetProperties();
            foreach (PropertyInfo item in proList)
            {
                string proName = item.Name;
                EntityXpathInfoProperyMapInfo proSchema = GetXpathProByName(proName, eInfo);
                if (proSchema == null)
                {
                    continue;
                }
                // 未设置映射
                if (string.IsNullOrEmpty(proSchema.Xpath))
                {
                    continue;
                }
                string proValue = GetValuleByXpath(xmlDoc, proSchema.Xpath);
                item.SetValue(t, proValue, null);
            }
            // 实体的属性经过业务逻辑变换
            t.Convert(eInfo.CustomerString);
            return t;
        }

        /// <summary>
        /// 根据属性名称获取映射信息
        /// </summary>
        /// <param name="proName">属性名称</param>
        /// <param name="eInfo">实体属性映射字典表</param>
        /// <returns>映射信息</returns>
        private EntityXpathInfoProperyMapInfo GetXpathProByName(string proName, EntityXpathInfo eInfo)
        {
            foreach (EntityXpathInfoProperyMapInfo item in eInfo.ProperyMapInfo)
            {
                if (item.Name.Equals(proName))
                {
                    return item;
                }
            }
            return null;
        }

        /// <summary>
        /// 将网页转为xml文档
        /// </summary>
        /// <param name="htmlString">网页地址</param>
        /// <returns></returns>
        private XmlDocument ConvertHtml2Xml(string uri, string encodingString)
        {
            StreamReader sReader = null;
            StringWriter sw = null;
            SgmlReader reader = null;
            XmlTextWriter writer = null;
            try
            {
                if (uri == String.Empty) uri = "http://www.XMLforASP.NET";
                HttpWebRequest req = (HttpWebRequest)WebRequest.Create(uri);
                HttpWebResponse res = null;
                try
                {
                    res = req.GetResponse() as HttpWebResponse;
                }
                catch
                {
                    throw new NullReferenceException("uri资源地址" + uri + "不存在或网络无法联通。");
                }
                Encoding encode = Encoding.GetEncoding("gb2312");
                sReader = new StreamReader(res.GetResponseStream(), encode, false);
                reader = new SgmlReader();
                reader.DocType = "HTML";
                // 标签一律转化为小写
                reader.CaseFolding = CaseFolding.ToLower;
                reader.InputStream = new StringReader(sReader.ReadToEnd());
                sw = new StringWriter();
                writer = new XmlTextWriter(sw);
                writer.Formatting = Formatting.Indented;
                while (reader.Read())
                {
                    if (reader.NodeType != XmlNodeType.Whitespace)
                    {
                        writer.WriteNode(reader, true);
                    }
                }
                string tmp = sw.ToString();
                if (string.IsNullOrEmpty(tmp))
                {
                    return new XmlDocument();
                }
                XmlDocument doc = new XmlDocument();
                doc.LoadXml(tmp);
                return doc;
            }
            catch (Exception exp)
            {
                if (writer != null)
                    writer.Close();
                if (reader != null)
                    reader.Close();
                if (sw != null)
                    sw.Close();
                if (sReader != null)
                    sReader.Close();
                throw exp;
            }
        }

        /// <summary>
        /// 根据文档的xpath获取属性值
        /// </summary>
        /// <param name="doc">xml文档</param>
        /// <param name="xpath">xpath</param>
        /// <returns>属性值</returns>
        private string GetValuleByXpath(XmlDocument doc, string xpath)
        {
            StringBuilder sb = new StringBuilder();
            XmlNodeList nodes = doc.SelectNodes(xpath);
            bool isAppend = false;
            foreach (XmlNode node in nodes)
            {
                sb.Append(node.InnerText + ",");
                isAppend = true;
            }
            if (isAppend == true)
            {
                sb.Remove(sb.Length - 1, 1);
            }
            return sb.ToString();
        }

        public string GetWellFormedHTML(string uri, string xpath)
        {
            StreamReader sReader = null;
            StringWriter sw = null;
            SgmlReader reader = null;
            XmlTextWriter writer = null;
            try
            {
                if (uri == String.Empty) uri = "http://www.XMLforASP.NET";
                HttpWebRequest req = (HttpWebRequest)WebRequest.Create(uri);
                HttpWebResponse res = (HttpWebResponse)req.GetResponse();
                sReader = new StreamReader(res.GetResponseStream());
                reader = new SgmlReader();
                reader.DocType = "HTML";
                // 标签一律转化为小写
                reader.CaseFolding = CaseFolding.ToLower;
                reader.InputStream = new StringReader(sReader.ReadToEnd());
                sw = new StringWriter();
                writer = new XmlTextWriter(sw);
                writer.Formatting = Formatting.Indented;
                while (reader.Read())
                {
                    if (reader.NodeType != XmlNodeType.Whitespace)
                    {
                        writer.WriteNode(reader, true);
                    }
                }
                if (xpath == null)
                {
                    return sw.ToString();
                }
                else
                {
                    StringBuilder sb = new StringBuilder();
                    string tmp = sw.ToString();
                    XmlDocument doc = new XmlDocument();
                    doc.LoadXml(tmp);
                    XmlNodeList nodes = doc.SelectNodes(xpath);
                    foreach (XmlNode node in nodes)
                    {
                        sb.Append(node.InnerText + "\n");
                    }
                    return sb.ToString();
                }
            }
            catch (Exception exp)
            {
                writer.Close();
                reader.Close();
                sw.Close();
                sReader.Close();
                return exp.Message;
            }
        }

    }
}
